﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using Lib.Helper;
using MSIACCSL2.AppParamServices;
using MSIACCSL2.Command;
using MSIACCSL2.RoleServices;
using MSIACCSL2.UserServices;
using MSIACCSL2.Views.User;
using WcfService1.DTO;
using GetListByCriteriaCompletedEventArgs = MSIACCSL2.UserServices.GetListByCriteriaCompletedEventArgs;
using GetListCompletedEventArgs = MSIACCSL2.UserServices.GetListCompletedEventArgs;

namespace MSIACCSL2.ViewModels
{
    public class UserViewModel : ViewModelBase
    {
        #region Delegates

        public delegate void Completed(Object param);

        #endregion

        private static string OrderType;
        private static string PropertySort;
        public static Mode mode;
        private static UserDTO _user;
        private static Add frmAdd;
        public static Completed OnSearchCompleted;
        private readonly AppParamServicesClient ParamClient;
        private readonly RoleServicesClient RoleClient;
        private readonly UserServicesClient client;
        private int CurrentPage;
        private ObservableCollection<int> Pages;
        private ObservableCollection<string> _Departments;
        private bool _IsBusy;
        private List<string> _errors;
        private Visibility _messageVisibility;
        private PagedCollectionView _pageSources;
        private ObservableCollection<RoleDTO> _roles;
        private PagedCollectionView _users;
        private Search frmSearch;
        private ValidationHandler validationHandler;

        public UserViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                client = new UserServicesClient();
                OnPageChanged = new DelegateCommand(PageIndexChanged, CanPageIndexChanged);
                Save = new DelegateCommand(SaveUser, CanSave);
                New = new DelegateCommand(NewUser, CanNew);
                Edit = new DelegateCommand(EditUser, CanEdit);
                Unload = new DelegateCommand(Release, CanUnload);
                SearchCommand = new DelegateCommand(SearchUser, CanSearch);
                SearchResultCommand = new DelegateCommand(SearchResult, CanSearchResult);
                SelectedCommand = new DelegateCommand(SelectRole, CanSelect);
                MessageVisibility = Visibility.Collapsed;
                RoleClient = new RoleServicesClient();
                ParamClient = new AppParamServicesClient();


                if (mode == Mode.Edit || mode == Mode.Search || mode == Mode.Add)
                {
                    GetRoles();
                    LoadDepartments();
                }
                else
                {
                    GetList(1, null);
                }
            }
        }

        public PagedCollectionView Users
        {
            get { return _users; }

            private set
            {
                if (Users == value) return;
                _users = value;

                int i = (CurrentPage*30);
                foreach (object user in Users)
                {
                    i += 1;

                    ((UserDTO) user).No = i;
                }

                FirePropertyChanged("Users");
                Users.CollectionChanged += User_CollectionChanged;
            }
        }

        public ObservableCollection<RoleDTO> Roles
        {
            get { return _roles; }
            private set
            {
                if (Roles == value) return;
                _roles = value;
                FirePropertyChanged("Roles");
            }
        }

        public ObservableCollection<string> Departments
        {
            get { return _Departments; }
            private set
            {
                if (Departments == value) return;
                _Departments = value;
                FirePropertyChanged("Departments");
            }
        }


        public PagedCollectionView PageSources
        {
            get { return _pageSources; }
            private set
            {
                if (PageSources == value) return;
                _pageSources = value;
                FirePropertyChanged("PageSources");
            }
        }


        public bool IsBusy
        {
            get { return _IsBusy; }
            internal set
            {
                _IsBusy = value;
                FirePropertyChanged("IsBusy");
            }
        }


        public long RecordCount { get; set; }

        //Buat binding ke child form waktu mau edit
        public static UserDTO User
        {
            get { return _user; }
            private set
            {
                if (User == value) return;
                _user = value;
                FirePropertyChanged2("User");
            }
        }


        public ICommand OnPageChanged { get; set; }
        public ICommand Save { get; set; }
        public ICommand New { get; set; }
        public ICommand Edit { get; set; }
        public ICommand Unload { get; set; }
        public ICommand SearchCommand { get; set; }
        public ICommand SearchResultCommand { get; set; }
        public ICommand SelectedCommand { get; set; }

        public List<string> Errors
        {
            get { return _errors; }
            private set
            {
                if (Errors == value) return;
                _errors = value;
                FirePropertyChanged("Errors");
            }
        }

        public Visibility MessageVisibility
        {
            get { return _messageVisibility; }
            private set
            {
                if (MessageVisibility == value) return;
                _messageVisibility = value;
                FirePropertyChanged("MessageVisibility");
            }
        }

        public void Complete(Object param)
        {
            OnSearchCompleted(param);
        }

        private void LoadDepartments()
        {
            ParamClient.GetAppParamListCompleted += ParamClient_GetAppParamListCompleted;
            ParamClient.GetAppParamListAsync("Departemen");
        }

        private void ParamClient_GetAppParamListCompleted(object sender, GetAppParamListCompletedEventArgs e)
        {
            ParamClient.GetAppParamListCompleted -= ParamClient_GetAppParamListCompleted;
            Departments = new ObservableCollection<string>();
            foreach (AppParamDTO appParamDto in e.Result)
                Departments.Add(appParamDto.AppParamValue);
            if (User != null)
            {
                if (!string.IsNullOrEmpty(User.Department))
                    User.Department = Departments.FirstOrDefault(x => x == User.Department);
            }
        }

        private void User_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (((PagedCollectionView) sender).SortDescriptions.Count > 0)
            {
                if (((PagedCollectionView) sender).SortDescriptions[0].PropertyName.ToLower() == "no") return;

                PropertySort = ((PagedCollectionView) sender).SortDescriptions[0].PropertyName;
                if (string.IsNullOrEmpty(OrderType))
                {
                    OrderType = "ASC";
                }
                else
                {
                    OrderType = OrderType == "ASC" ? OrderType = "DESC" : OrderType = "ASC";
                }
                GetList(1, PropertySort);
            }
        }


        public void SaveUser(Object user)
        {
            User = (UserDTO) user;
            Validate();
            if (Errors.Count > 0) return;
            //Clear all Role before save it
            User.Roles = new ObservableCollection<RoleDTO>();
            foreach (RoleDTO roleDto in Roles)
            {
                if (roleDto.IsSelected)
                    User.Roles.Add(roleDto);
            }
            if (string.IsNullOrEmpty(User.UserID)) User.UserID = Guid.NewGuid().ToString();
            User.created_by = GlobalVar.User.UserID;
            User.modified_by = GlobalVar.User.UserID;
            client.SaveUserCompleted += client_SaveUserCompleted;
            client.SaveUserAsync(User);
        }


        private void client_SaveUserCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error != null) Validate(e.Error.ToString());
            client.SaveUserCompleted -= client_SaveUserCompleted;
            MessageBox.Show("Success");
            frmAdd.DialogResult = true;
            Refresh();
        }


        public void GetList(int? page, string sortProp)
        {
            IsBusy = true;
            client.GetListCompleted += client_GetListCompleted;
            client.GetListAsync(page ?? 1, sortProp, OrderType);
        }

        private void client_GetListCompleted(object sender, GetListCompletedEventArgs e)
        {
            RecordCount = e.recordCount;
            if (PageSources == null) CreatePageNumber();
            client.GetListCompleted -= client_GetListCompleted;
            Users = new PagedCollectionView(e.Result);
            IsBusy = false;
            Complete(this);
        }

        public void GetRoles()
        {
            RoleClient.GetListCompleted += RoleClient_GetListCompleted;
            RoleClient.GetListAsync(1, null, null);
        }

        private void RoleClient_GetListCompleted(object sender, RoleServices.GetListCompletedEventArgs e)
        {
            RoleClient.GetListCompleted -=
                RoleClient_GetListCompleted;
            IEnumerable<RoleDTO> query = from r in e.Result
                                         select new RoleDTO {RoleId = r.RoleId, RoleName = r.RoleName};
            Roles = new ObservableCollection<RoleDTO>(query);

            if (mode != Mode.Add && mode != Mode.Edit) return;
            if (User.Roles == null) return;
            foreach (RoleDTO roleDto in Roles)
            {
                if (User.Roles.Any(u => u.RoleId == roleDto.RoleId))
                    roleDto.IsSelected = true;
            }
        }


        private void NewUser(Object param)
        {
            mode = Mode.Add;
            User = new UserDTO();
            frmAdd = new Add();
            frmAdd.Show();
        }


        public static void EditUser(Object param)
        {
            mode = Mode.Edit;
            User = (UserDTO) param;
            frmAdd = new Add();
            frmAdd.Show();
        }


        private void SearchUser(Object param)
        {
            mode = Mode.Search;
            frmSearch = new Search();
            frmSearch.Show();
        }


        private void SearchResult(Object param)
        {
            var criteria = new Dictionary<string, object>();
            frmSearch = (Search) param;
            if (!String.IsNullOrEmpty(frmSearch.txtUserName.Text)) criteria.Add("UserName", frmSearch.txtUserName.Text);
            if (!String.IsNullOrEmpty(frmSearch.txtNamaLengkap.Text))
                criteria.Add("NamaLengkap", frmSearch.txtNamaLengkap.Text);
            if (!String.IsNullOrEmpty(frmSearch.txtEmail.Text)) criteria.Add("Email", frmSearch.txtEmail.Text);
            if (!String.IsNullOrEmpty(frmSearch.txtTelp.Text)) criteria.Add("hpp_awal", frmSearch.txtTelp.Text);
            string expression = string.Empty;
            if (frmSearch.rblOr.IsChecked ?? false) expression = "OR";
            else expression = "AND";
            UserSearch(criteria, expression);
        }

        private void UserSearch(Dictionary<String, Object> criteria, string expression)
        {
            frmSearch.DialogResult = true;
            IsBusy = true;
            Complete(this);
            client.GetListByCriteriaCompleted += client_GetListByCriteriaCompleted;
            client.GetListByCriteriaAsync(criteria, expression, 1);
        }

        private void client_GetListByCriteriaCompleted(object sender, GetListByCriteriaCompletedEventArgs e)
        {
            Users = new PagedCollectionView(e.Result);
            RecordCount = e.recordCount;
            CreatePageNumber();
            IsBusy = false;
        }


        private void CreatePageNumber()
        {
            Pages = new ObservableCollection<int>();
            for (int i = 0; i < RecordCount; i++)
            {
                Pages.Add(i);
            }
            PageSources = new PagedCollectionView(Pages);
        }


        private void PageIndexChanged(Object pageIndex)
        {
            //Jika Pertama kali jangan di Getlagi
            User = null;
            if (Users != null && CurrentPage != (int) pageIndex)
            {
                CurrentPage = (int) pageIndex;
                if (String.IsNullOrEmpty(PropertySort))
                    GetList((int) pageIndex + 1, null);
                else GetList((int) pageIndex + 1, PropertySort);
            }
        }


        public bool CanPageIndexChanged(Object param)
        {
            return true;
        }


        public bool CanSave(Object param)
        {
            return true;
        }


        public bool CanNew(Object param)
        {
            return true;
        }

        public bool CanEdit(Object param)
        {
            return true;
        }


        public bool CanUnload(Object param)
        {
            return true;
        }


        public bool CanSearch(Object param)
        {
            return true;
        }

        public bool CanSearchResult(Object param)
        {
            return true;
        }


        public void Release(Object param)
        {
            param = null;
            User = null;
            OrderType = null;
            PropertySort = null;
            mode = Mode.Idle;
        }


        public void Refresh()
        {
            if (Users == null)
                GetList(1, null);
            else
                Complete(this);
        }


        public void Validate(string error = null)
        {
            Errors = new List<string>();
            if (string.IsNullOrEmpty(User.UserName) || User.UserName.Length < 3)
                Errors.Add("Username tidak boleh kurang dari 3 karakter");
            if (string.IsNullOrEmpty(User.Password) || User.Password.Length < 3)
                Errors.Add("Password tidak boleh kurang dari 3 karakter");
            if (! string.IsNullOrEmpty(error))
                Errors.Add(error);

            if (Errors.Count > 0)
            {
                MessageVisibility = Visibility.Visible;
            }
            else
            {
                MessageVisibility = Visibility.Collapsed;
            }
        }

        public bool CanSelect(Object param)
        {
            return true;
        }

        public void SelectRole(Object param)
        {
            User.Roles.Add((RoleDTO) param);
        }
    }


    public class UserWrapViewModel : ViewModelBase
    {
        private readonly UserServicesClient client;

        public UserWrapViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                EditCommand = new DelegateCommand(Edit, CanEditCommand);
                DeleteCommand = new DelegateCommand(Delete, CanDeleteCommand);
                client = new UserServicesClient();
            }
        }


        public ICommand EditCommand { get; set; }
        public ICommand DeleteCommand { get; set; }


        public bool CanEditCommand(Object param)
        {
            return true;
        }

        public bool CanDeleteCommand(Object param)
        {
            return true;
        }

        public void Edit(Object param)
        {
            UserViewModel.EditUser(param);
        }

        public void Delete(Object param)
        {
            client.DeleteUserCompleted += client_DeleteCompleted;
            client.DeleteUserAsync((UserDTO) param);
        }

        private void client_DeleteCompleted(object sender, AsyncCompletedEventArgs e)
        {
            client.DeleteUserCompleted -= client_DeleteCompleted;
            MessageBox.Show("Delete Success!");
            UserViewModel.mode = Mode.Idle;
            var VM = new UserViewModel();
        }
    }
}